package com.cr.admin.business.news.dao.repository.impl;

import cn.dev33.satoken.stp.StpUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.cr.admin.business.news.dao.mapper.NewsMapper;
import com.cr.admin.business.news.dao.repository.NewsRepository;
import com.cr.admin.business.news.pojo.entity.News;
import com.cr.admin.business.news.pojo.param.NewsCreateParam;
import com.cr.admin.business.news.pojo.query.NewsQuery;
import com.cr.admin.business.news.pojo.vo.NewsCategoryVO;
import com.cr.admin.business.news.pojo.vo.NewsDetailsVO;
import com.cr.admin.business.news.pojo.vo.NewsStatusVO;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.DocWriteResponse;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import java.util.Date;
import java.util.List;

@Slf4j
@Repository
public class NewsRepositoryImpl implements NewsRepository {
    @Autowired
    private NewsMapper newsMapper;

    @Override
    public List<News> selectList(NewsQuery newsQuery) {
        // 创建查询条件包装器
        QueryWrapper<News> queryWrapper = new QueryWrapper<>();
        // 如果newsQuery中的标题不为null，则添加标题模糊查询条件
        if (newsQuery.getTitle() != null) {
            queryWrapper.like("title", newsQuery.getTitle());
        }
        // 如果newsQuery中的分类ID不为null，则添加分类ID模糊查询条件
        if (newsQuery.getCategoryId() != null) {
            queryWrapper.like("category_id", newsQuery.getCategoryId());
        }
        // 如果newsQuery中的状态不为null，则添加状态模糊查询条件
        if (newsQuery.getStatus() != null) {
            queryWrapper.like("status", newsQuery.getStatus());
        }
        // 按创建时间倒序排序
        queryWrapper.orderByDesc("created_time");
        // 执行数据库查询并返回结果列表
        return newsMapper.selectList(queryWrapper);
    }

    @Override
    public List<NewsCategoryVO> selectCategory() {
        log.info("*** 获取资讯类别 入参：无");
        return newsMapper.selectCategory();
    }

    @Override
    public List<NewsStatusVO> selectNewsStatus() {
        return newsMapper.selectNewsStatus();
    }

    @Override
    public NewsDetailsVO selectDetailsById(Integer id) {
        log.debug("查询资讯详情：入参 id = {}", id);
        NewsDetailsVO detailsVO = new NewsDetailsVO();
        detailsVO = newsMapper.selectDetailsById(id);
        log.info("查询资讯详情：入参 id = {}，出参 = {}", id, detailsVO);
        return detailsVO;
    }

    @Override
    public void saveCreate(NewsCreateParam param) {
        News news = new News();
        if (param.getId() == null) {
            log.info("插入资讯：入参 param = {}", param);
            BeanUtils.copyProperties(param, news);
            news.setCreatedBy(StpUtil.getSession().get("nickname").toString());
            news.setCreatedTime(new Date());
            newsMapper.insertNews(news);
        } else {
            log.info("更新资讯：入参 param = {}", param);
            BeanUtils.copyProperties(param, news);
            newsMapper.updateNews(news);
            //更新ES缓存
            updateES(news);
            //todo  异步插入es缓存 可能会发生的问题  数据库插入成功 es插入失败 怎么解决 用消息队列  es作为消费者    消息队列 解决
        }
    }


    @Override
    public void deleteByIds(List<Long> ids) {
        log.debug("删除资讯：入参 ids = {}",ids);
        newsMapper.deleteByIds(ids);
        //删除es缓存
        deleteEs(ids);
    }

    @Override
    public void sendNews(int id) {
        log.info("发布资讯：入参 id= {}",id);
        newsMapper.updateNewsById(id);
        News news = newsMapper.selectById(id);
        log.info("发布资讯：入参 id= {}，出参 = {}", id, news);

        //插入ES缓存
        insertES(newsMapper.selectById(id));
    }



    @Autowired
    private RestHighLevelClient client;

    //插入ES缓存
    private void insertES(News news) {
        log.info("插入一条ES缓存：{}", news);

        //没有连接es的客户端 不需要创建索引 已经创建lbs_store
        IndexRequest indexRequest=new IndexRequest("news");
        //指定索引,指定id,转化数据成为json 写入文档doc
        indexRequest.id(news.getId()+"");
        //填写 文档具体数据 转化成json
        String sourceNews= JSON.toJSONString(news);
        log.info("当前新增:{}",sourceNews);
        indexRequest.source(sourceNews, XContentType.JSON);
        try{
            client.index(indexRequest, RequestOptions.DEFAULT);
        }catch (Exception e){
            log.error("新增文档异常",e);
        }
    }

    //更新ES缓存
    private void updateES(News news) {
        log.info("更新一条ES文档：{}", news);

        UpdateRequest updateRequest = new UpdateRequest("news", news.getId().toString());

        // 填写 文档具体数据 转化成json
        String sourceNews = JSON.toJSONString(news);

        // 使用JSONBuilder或XContentBuilder可以构建更复杂的更新脚本，但在这里我们直接使用upsert
        updateRequest.doc(sourceNews, XContentType.JSON);
        // 或者使用 upsert 参数，如果文档不存在则插入
        // updateRequest.upsert(sourceNews, XContentType.JSON);

        try {
            UpdateResponse updateResponse = client.update(updateRequest, RequestOptions.DEFAULT);
            if (updateResponse.getResult() == DocWriteResponse.Result.UPDATED) {
                log.info("文档更新成功");
            } else if (updateResponse.getResult() == DocWriteResponse.Result.CREATED) {
                log.info("文档创建成功，因为它之前不存在");
            }
        } catch (Exception e) {
            log.error("更新文档异常", e);
        }
    }

    //删除ES缓存 通过id
    private void deleteEs(List<Long> ids){
        log.info("删除ES文档：id = {}", ids);
        for (Long id : ids) {
            DeleteRequest deleteRequest = new DeleteRequest("news", id.toString());
            try {
                DeleteResponse deleteResponse = client.delete(deleteRequest, RequestOptions.DEFAULT);
                if (deleteResponse.getResult() == DocWriteResponse.Result.DELETED) {
                    log.info("文档删除成功");
                } else if (deleteResponse.getResult() == DocWriteResponse.Result.NOT_FOUND) {
                    log.info("文档不存在");
                }
            } catch (Exception e) {
                log.error("删除文档异常", e);
            }
        }
    }


}
